package com.why.simpleboot.core.core.factory;

import com.why.simpleboot.core.annotation.mvc.GetMapping;
import com.why.simpleboot.core.annotation.mvc.PostMapping;
import com.why.simpleboot.core.annotation.mvc.RestController;
import com.why.simpleboot.core.common.utils.UrlUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @program: why-simpleboot-framework
 * @description:负责启动的时候，加载url与method
 * @author: @why
 * @create: 2021-05-22 17:12
 **/
public class RouterFactory {
    private Logger log = LoggerFactory.getLogger(RouterFactory.class);
    /**
     * //类初始化的时候就完成对get和post这2个mapping的处理
     * //每个url都对应着一个方法。目前，这里存放的是经过处理后的路径所匹配的方法
     * eg--->^/hello/$&  ---->method
     */
    public static final Map<String, Method> POST_MAPPING_MAP = new HashMap<>();
    public static final Map<String, Method> GET_MAPPING_MAP = new HashMap<>();
    /**
     * 每个正则URL所对应的原URL地址
     * ^/hello/$&  ----> /hello/
     */
    public static final Map<String, String> GET_URL_MAP = new HashMap<>();
    public static final Map<String, String> POST_URL_MAP = new HashMap<>();

    /**
     * 完成方法和url的映射处理，缓存所有被注解标注的方法 将其缓存起来。
     *
     * @param classes
     */
    public void loadRouters(ConcurrentHashMap<Class<? extends Annotation>, Set<Class<?>>> classes) {

        Set<Class<?>> routerClasses = classes.get(RestController.class);
        if (routerClasses.size() > 0) {
            log.info("loadRouters start...");
            for (Class<?> routers : routerClasses) {
                RestController restController = routers.getAnnotation(RestController.class);
                //拿到当前controller的url
                String baseUrl = restController.value();
                //拿到当前类的所有方法
                Method[] methods = routers.getDeclaredMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(GetMapping.class)) {
                        GetMapping getMapping = method.getAnnotation(GetMapping.class);
                        String url = getMapping.value();
//                    完成路径拼接并将其转为正则表达式
                        addMapping(baseUrl, method, url, GET_MAPPING_MAP, GET_URL_MAP);

                    } else if (method.isAnnotationPresent(PostMapping.class)) {
                        PostMapping postMapping = method.getAnnotation(PostMapping.class);
                        String url = postMapping.value();
                        addMapping(baseUrl, method, url, POST_MAPPING_MAP, POST_URL_MAP);
                    }
                }


            }

            log.info("The {GET_URL_MAP} path after loading is{}", GET_URL_MAP);
            log.info("The {GET_MAPPING_MAP}path after loading is{}", GET_MAPPING_MAP);
            log.info("The {POST_MAPPING_MAP} path after loading is{}", POST_MAPPING_MAP);
            log.info("The {POST_URL_MAPds} path after loading is{}", POST_URL_MAP);
        }

    }

    /**
     * 将对应请求地址放入mapp集合
     *
     * @param baseUrl：restController的url
     * @param method：方法
     * @param url：getmapping/postmapping里面的url
     * @param methodMap：方法map集合，一个url地址对应一个方法. eg:--->^/hello/$&  ---->method
     * @param urlMap：格式化后的url--->原始url         eg:^/hello/$&  ----> /hello/
     */
    private void addMapping(String baseUrl,
                            Method method,
                            String url,
                            Map<String, Method> methodMap,
                            Map<String, String> urlMap) {
        StringBuilder sb = new StringBuilder();
        sb.append(baseUrl);
        sb.append(url);
        String formatUrl = UrlUtils.formatUrl(sb.toString());
        if (methodMap.containsKey(formatUrl) || urlMap.containsKey(formatUrl)) {
            throw new IllegalArgumentException("Ambiguous url found.");
        }
        methodMap.put(formatUrl, method);
        urlMap.put(formatUrl, sb.toString());

    }


}
